package cn.sc.summer.gateway.handler;

import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.RandomUtil;
import cn.sc.summer.gateway.exception.CommonException;
import cn.sc.summer.gateway.util.IPUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import cn.sc.summer.constant.gateway.GatewayConstant;
import cn.sc.summer.constant.rabbit.RabbitConstant;
import cn.sc.summer.constant.regex.RegexConstant;
import cn.sc.summer.constant.sms.SmsConstant;
import cn.sc.summer.constant.util.DateUtilX;
import cn.sc.summer.constant.model.Result;
import cn.sc.summer.rabbitmq.builder.RabbitBuilder;
import cn.sc.summer.rabbitmq.builder.RabbitMessageBuilderDirector;
import cn.sc.summer.redis.util.RedisHelper;
import cn.sc.summer.sms.util.SmsUtil;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.lang.NonNull;
import org.springframework.web.reactive.function.server.HandlerFunction;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * 类名：发送短信验证码拦截器
 *
 * @author a-xin
 * @date 2023/10/17 13:13
 */
@Slf4j
@Configuration
@NoArgsConstructor
@AllArgsConstructor
public class CreateSmsCodeHandler implements HandlerFunction<ServerResponse> {

    @Value("${sms.phone:45}")
    private Integer PHONE_SMS_NUM;

    @Value("${sms.phoneMax:50}")
    private Integer PHONE_SMS_NUM_MAX;

    @Value("${sms.ipaddress:95}")
    private Integer IP_ADDRESS_SMS_NUM;

    @Value("${sms.ipMax:100}")
    private Integer IP_ADDRESS_SMS_NUM_MAX;

    @Value("${sms.expireTime:5}")
    private Integer SMS_EXPIRE_TIME;

    @Resource
    private RabbitTemplate rabbitTemplate;

    @Override
    @NonNull
    public Mono<ServerResponse> handle(@NonNull ServerRequest serverRequest) {
        ServerRequest.Headers headers = serverRequest.headers();
        String phone = headers.firstHeader("phone");
        String hostAddress = IPUtil.getIpAddr(serverRequest.exchange().getRequest());
        if (CharSequenceUtil.isBlank(phone) || (CharSequenceUtil.isNotBlank(phone) && !phone.matches(RegexConstant.TEL_REGEX))) {
            return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(Mono.just(JSON.toJSONString(Result.fail("The phone number is not formatted correctly！"))), String.class);
        }

        if (Boolean.TRUE.equals(RedisHelper.hasKey(GatewayConstant.SMS_CODE_KEY_IP_ADDRESS + hostAddress)) && Integer.parseInt(String.valueOf(RedisHelper.get(GatewayConstant.SMS_CODE_KEY_IP_ADDRESS + hostAddress))) > IP_ADDRESS_SMS_NUM_MAX) {
            return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(Mono.just(JSON.toJSONString(Result.fail("The maximum number of SMS messages sent today has been reached！"))), String.class);
        }

        if (Boolean.TRUE.equals(RedisHelper.hasKey(GatewayConstant.SMS_CODE_KEY_PHONE + phone)) && Integer.parseInt(String.valueOf(RedisHelper.get(GatewayConstant.SMS_CODE_KEY_PHONE + phone))) > PHONE_SMS_NUM_MAX) {
            return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(Mono.just(JSON.toJSONString(Result.fail("The maximum number of SMS messages sent today has been reached！"))), String.class);
        }

        checkSms(serverRequest);

        //保存验证码信息
        String randomKey = RandomUtil.randomString(16);
        String smsCode = RandomUtil.randomString(6);
        Map<String, String> paramsMap = new HashMap<>();
        paramsMap.put("smsCode", smsCode);

        JSONObject jsonMessage = new RabbitMessageBuilderDirector(new RabbitBuilder()).build();
        JSONObject message = new JSONObject();
        message.put("ipAddress", hostAddress);
        message.put("phone", phone);
        String key = SmsConstant.SMS_TEMPLATE + SmsConstant.SMS_TEMPLATE_LOG_IN;
        if (Boolean.TRUE.equals(!RedisHelper.hasKey(key)) || Boolean.TRUE.equals(!RedisHelper.hHasKey(key, "templateId"))) {
            throw new CommonException("There is no SMS template of LOGIN!");
        }
        String templateId = Objects.requireNonNull(RedisHelper.hGet(key, SmsConstant.SMS_TEMPLATE_ID)).toString();
        message.put("template", templateId);
        message.put("params", JSON.toJSONString(paramsMap));

        SmsUtil.sendSmsMessage(phone, templateId, smsCode);
        log.warn("==> Start sending text messages to your phone: {}, Mobile phone number : {}, SMS verification code : {}", randomKey, phone, smsCode);
        jsonMessage.put(RabbitConstant.MESSAGE_KEY, message.toJSONString());
        rabbitTemplate.convertAndSend(RabbitConstant.SMS_RECORD_EXCHANGE,
                RabbitConstant.SMS_RECORD_ROUTING_KEY,
                jsonMessage.toJSONString());
        //设置有效期
        RedisHelper.set(GatewayConstant.SMS_CODE_KEY + randomKey, smsCode, 60L * SMS_EXPIRE_TIME, TimeUnit.SECONDS);
        serverRequest.exchange().getResponse().getHeaders().set("smsRandomKey", randomKey);
        return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(Mono.just(JSON.toJSONString(Result.success(randomKey))), String.class);
    }

    public void checkSms(ServerRequest serverRequest) {

        ServerRequest.Headers headers = serverRequest.headers();
        String phone = headers.firstHeader("phone");

        ServerHttpRequest request = serverRequest.exchange().getRequest();
        String hostAddress = IPUtil.getIpAddr(request);

        JSONObject jsonMessage = new RabbitMessageBuilderDirector(new RabbitBuilder()).build();
        Map<String, Object> message = new HashMap<>();
        message.put("ipAddress", hostAddress);
        message.put("phone", phone);

        String ipKey = GatewayConstant.SMS_CODE_KEY_IP_ADDRESS + hostAddress;
        if (Boolean.TRUE.equals(RedisHelper.hasKey(ipKey)) && Integer.parseInt(String.valueOf(RedisHelper.get(ipKey))) > IP_ADDRESS_SMS_NUM) {
            String frequency = String.valueOf(RedisHelper.get(ipKey));
            log.error("==> IP地址：{} 当天发送短信已超 {} 条，现已发送：{} 条！", hostAddress, IP_ADDRESS_SMS_NUM, frequency);
            message.put("frequency", frequency);
            message.put("type", "hostAddress");
        }
        RedisHelper.incr(ipKey, 1);
        RedisHelper.expire(ipKey, DateUtilX.getLongTimeToTomorrow(), TimeUnit.MILLISECONDS);

        String redisKey = GatewayConstant.SMS_CODE_KEY_PHONE + phone;
        if (Boolean.TRUE.equals(RedisHelper.hasKey(redisKey)) && Integer.parseInt(String.valueOf(RedisHelper.get(redisKey))) > PHONE_SMS_NUM) {
            String frequency = String.valueOf(RedisHelper.get(redisKey));
            log.error("==> 手机号：{} 当天发送短信已超 {} 条，现已发送：{} 条！", phone, PHONE_SMS_NUM, frequency);
            message.put("frequency", frequency);
            message.put("type", "phone");
        }

        jsonMessage.put(RabbitConstant.MESSAGE_KEY, JSONObject.toJSONString(message));
        rabbitTemplate.convertAndSend(RabbitConstant.SMS_ERROR_RECORD_EXCHANGE,
                RabbitConstant.SMS_ERROR_RECORD_ROUTING_KEY,
                jsonMessage.toJSONString());

        RedisHelper.incr(redisKey, 1);
        RedisHelper.expire(redisKey, DateUtilX.getLongTimeToTomorrow(), TimeUnit.MILLISECONDS);

    }

}
